#pragma once

#include "Mesh.h"
#include "Calculus.h"

namespace Mesh
{
	// 多边形类型
	using Polygon = std::deque<point3f>;

	// 样条基类
	class Spline
	{
	protected:
		int m_u, m_v;					 // u,v 方向的控制点数
		std::deque<point3f> m_ctrlPoint; // 控制点数组

	public:
		Spline(int up, int vp = 1);

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:10
		 *
		 * @description: 基础设置
		 */

		void setCtrlPoints(std::deque<point3f> pList); // 设置控制点
		std::deque<point3f> getCtrlPolygon() const;	   // 获得控制点数组

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:11
		 *
		 * @description: 曲线曲面参数信息
		 */

		virtual float paramUBegin() const = 0; // 获得 u 起始参数
		virtual float paramUEnd() const = 0;   // 获得 u 终点参数
		virtual float paramVBegin() const = 0; // 获得 v 起始参数
		virtual float paramVEnd() const = 0;   // 获得 v 终点参数

		virtual int uDegree() const = 0; // 获取 u 次数信息
		virtual int vDegree() const = 0; // 获取 v 次数信息

		virtual float paramU(point3f p) const = 0;					// 已知曲线上的点，反求参数 u
		virtual LinearAlgebra::Vector paramUV(point3f p) const = 0; // 已知曲面上的点，反求参数 u,v

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:09
		 *
		 * @description: 计算曲线或曲面上的点
		 */

		virtual point3f calculateU(float u) const = 0;			 // 获得 u 参数点
		virtual point3f calculateUV(float u, float v) const = 0; // 获得 (u,v) 参数点

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 15:02
		 *
		 * @description: 输出曲线或网格
		 */

		void output(int udivide, float *array) const;			   // 输出曲线数组
		void output(int udivide, int vdivide, float *array) const; // 输出网格数组
		void control(float *array) const;						   // 输出控制点数组
		HEMesh toMesh(int udivide, int vdivide) const;			   // 转换为网格
	};

	// Bezier 曲线和曲面
	class Bezier : public Spline
	{
	public:
		Bezier(int up, int vp = 1) : Spline(up, vp) {}

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:11
		 *
		 * @description: 曲线曲面参数信息
		 */

		virtual float paramUBegin() const; // 获得 u 起始参数
		virtual float paramUEnd() const;   // 获得 u 终点参数
		virtual float paramVBegin() const; // 获得 v 起始参数
		virtual float paramVEnd() const;   // 获得 v 终点参数

		virtual int uDegree() const; // 获取 u 次数信息
		virtual int vDegree() const; // 获取 v 次数信息

		virtual float paramU(point3f p) const;					// 已知曲线上的点，反求参数 u
		virtual LinearAlgebra::Vector paramUV(point3f p) const; // 已知曲面上的点，反求参数 u,v

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:09
		 *
		 * @description: 计算曲线或曲面上的点
		 */

		virtual point3f calculateU(float u) const;			 // 获得 u 参数点
		virtual point3f calculateUV(float u, float v) const; // 获得 (u,v) 参数点

		point3f subdivide(std::deque<point3f> &pList, float t) const;		   // 曲线细分过程
		point3f subdivide(std::deque<point3f> &pList, float u, float v) const; // 曲面细分过程
	};

	// B 样条曲线和曲面
	class BSpline : public Spline
	{
	protected:
		// 节点向量
		std::deque<float> m_uKnot;
		std::deque<float> m_vKnot;

	public:
		BSpline(int up, int vp = 1) : Spline(up, vp) {}

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:11
		 *
		 * @description: 曲线曲面参数信息
		 */

		virtual float paramUBegin() const; // 获得 u 起始参数
		virtual float paramUEnd() const;   // 获得 u 终点参数
		virtual float paramVBegin() const; // 获得 v 起始参数
		virtual float paramVEnd() const;   // 获得 v 终点参数

		virtual int uDegree() const; // 获取 u 次数信息
		virtual int vDegree() const; // 获取 v 次数信息

		virtual float paramU(point3f p) const;					// 已知曲线上的点，反求参数 u
		virtual LinearAlgebra::Vector paramUV(point3f p) const; // 已知曲面上的点，反求参数 u,v

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 15:13
		 *
		 * @description: 设置基本参数
		 */

		void uniformUKnot(int deg, float start, float end); // 创建 u 均匀节点向量
		void uniformVKnot(int deg, float start, float end); // 创建 v 均匀节点向量
		void setUKnot(std::deque<float> v);					// 设置 u 节点向量
		void setVKnot(std::deque<float> v);					// 设置 v 节点向量

		/**
		 * @file Spline.h
		 * @author xingyifan
		 * @date 2022-11-26 14:09
		 *
		 * @description: 计算曲线或曲面上的点
		 */

		virtual point3f calculateU(float u) const;			 // 获得 u 参数点
		virtual point3f calculateUV(float u, float v) const; // 获得 (u,v) 参数点

		point3f subdivide(std::deque<float> &kList, std::deque<point3f> &pList, float t) const;										 // 曲线细分过程
		point3f subdivide(std::deque<float> &ukList, std::deque<float> &vkList, std::deque<point3f> &pList, float u, float v) const; // 曲面细分过程
	};

	/**
	 * @file Spline.h
	 * @author xingyifan
	 * @date 2022-12-02 16:28
	 *
	 * @description: 检测算法，用于平面样条曲线
	 */

	Polygon convexHull2D(Polygon &polygon);			 // 计算并返回平面多边形的凸包
	bool inHullInner2D(point3f p, Polygon &polygon); // 检查点是否在平面多边形的凸包内部
};